package com.haohope.excel.utils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;


public class DateUtil {
	private static Map<String,DateFormat> DateFormatMap = new HashMap<String,DateFormat>();
	static {
		DateFormatMap.put("yyyy-MM-dd HH:mm:ss", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
		DateFormatMap.put("yyyy-MM-dd HH:mm", new SimpleDateFormat("yyyy-MM-dd HH:mm"));
		DateFormatMap.put("yyyy-MM-dd HH", new SimpleDateFormat("yyyy-MM-dd HH"));
		DateFormatMap.put("yyyy-MM-dd", new SimpleDateFormat("yyyy-MM-dd"));
		DateFormatMap.put("yyyy-MM", new SimpleDateFormat("yyyy-MM"));
		DateFormatMap.put("yyyy", new SimpleDateFormat("yyyy"));
		
		DateFormatMap.put("MM", new SimpleDateFormat("MM"));
		DateFormatMap.put("dd", new SimpleDateFormat("dd"));
		DateFormatMap.put("HH", new SimpleDateFormat("HH"));
		DateFormatMap.put("mm", new SimpleDateFormat("mm"));
		DateFormatMap.put("ss", new SimpleDateFormat("mm"));
		
		DateFormatMap.put("MM-dd", new SimpleDateFormat("MM-dd"));
		DateFormatMap.put("dd HH", new SimpleDateFormat("dd HH"));
		DateFormatMap.put("HH:mm", new SimpleDateFormat("HH:mm"));
		DateFormatMap.put("mm:ss", new SimpleDateFormat("mm:ss"));
		
		DateFormatMap.put("MM-dd HH", new SimpleDateFormat("MM-dd HH"));
		DateFormatMap.put("dd HH:mm", new SimpleDateFormat("dd HH:mm"));
		DateFormatMap.put("HH:mm:ss", new SimpleDateFormat("HH:mm:ss"));
		
		DateFormatMap.put("MM-dd HH:mm", new SimpleDateFormat("MM-dd HH:mm"));
		DateFormatMap.put("dd HH:mm:ss", new SimpleDateFormat("dd HH:mm:ss"));
		
		DateFormatMap.put("MM-dd HH:mm:ss", new SimpleDateFormat("MM-dd HH:mm:ss"));
		
	}
	public static DateFormat getDateFormat(String formate) {
		return DateFormatMap.get("yyyy-MM-dd HH:mm:ss");
	}
    /**
             * 给时间加上几个小时
     * @param day
     * @param min
     * @return
     */
    public static String addDateMinute(String day, int min){   
    	DateFormat format = getDateFormat("yyyy-MM-dd HH:mm:ss");
    	Date date = null;   
    	try {   
    		date = format.parse(day);   
    	} catch (Exception ex) {   
    		ex.printStackTrace();   
    	}   
    	if (date == null)   
    		return "";   
    	Calendar cal = Calendar.getInstance();   
    	cal.setTime(date);   
    	cal.add(Calendar.MINUTE, min);
    	date = cal.getTime();   
    	cal = null;   
    	return format.format(date); 
    }
	/**
	 * 根据时间字符串返回Date对象
	 * @param dateStr
	 * @return
	 */
	public static Date getDateByStr(String dateStr) {
		if(StringUtils.isEmpty(dateStr)){
			return null;
		}
		DateFormat formatter = null;
		if (dateStr.length() >= 10 && dateStr.length() < 16)
			formatter = getDateFormat("yyyy-MM-dd");
		else if (dateStr.length() >= 16 && dateStr.length() < 19)
			formatter = getDateFormat("yyyy-MM-dd HH:mm");
		else if (dateStr.length() >= 19)
			formatter = getDateFormat("yyyy-MM-dd HH:mm:ss");
		else {
			return null;
		}
		try {
			return formatter.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static Date getMinMonthDate(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DATE, 1);
		return DateUtil.get00_00_00Date(cal.getTime());
	}

	public static Date getMaxMonthDate(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DATE, 1);
		cal.add(Calendar.MONTH, 1);
		cal.add(Calendar.DATE, -1);
		return DateUtil.get23_59_59Date(cal.getTime());
	}

	public static Date getStartDayDate(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DAY_OF_WEEK, 1);
		return DateUtil.get00_00_00Date(cal.getTime());
	}

	public static Date getEndDayDate(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DAY_OF_WEEK, 7);

		return DateUtil.get23_59_59Date(cal.getTime());
	}

	/**
	 * 根据时间字符串返回最大Date对象
	 * 
	 * @param dateStr
	 *            ,可以接受3种格式分别是:yyyy-MM-dd,yyyy-MM-dd HH:mm,yyyy-MM-dd HH:mm:ss
	 * @return
	 */
	public static Date getMaxDateByStr(String dateStr) {
		DateFormat formatter = null;
		if (dateStr.length() == 10) {
			formatter = getDateFormat("yyyy-MM-dd HH:mm:ss");
			dateStr += " 23:59:59";
		} else {
			return null;
		}
		try {
			return formatter.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 根据时间字符串返回最小Date对象
	 * 
	 * @param dateStr
	 *            ,可以接受3种格式分别是:yyyy-MM-dd
	 * @return
	 */
	public static Date getMinDateByStr(String dateStr) {
		DateFormat formatter = null;
		if (dateStr.length() == 10) {
			formatter = getDateFormat("yyyy-MM-dd HH:mm:ss");
			dateStr += " 00:00:00";
		} else {
			return null;
		}
		try {
			return formatter.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 根据时间字符串返回Date对象
	 * 
	 * @param dateStr
	 *            ,可以接受3种格式分别是:yyyy-MM-dd,yyyy-MM-dd HH:mm,yyyy-MM-dd HH:mm:ss
	 * @return
	 */
	public static Date getDateByStr(String dateStr, String formatters) {
		DateFormat formatter = null;
		formatter = getDateFormat(formatters);
		try {
			return formatter.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	
	@SuppressWarnings("deprecation")
	public static Date getDateYMDByStr(String dateStr){
		if(dateStr.contains("T") && !dateStr.contains("GMT+")) {
			return getDateByStr(dateStr,"yyyy-MM-dd'T'");
		}else if(dateStr.contains("GMT+")) {
			//GMT+
			Date date_ = new Date(dateStr);
			String datestr_ = getStrYMDByDate(date_);
			return getDateByStr(datestr_,"yyyy-MM-dd");
		}
		return getDateByStr(dateStr,"yyyy-MM-dd");
	}
	
	@SuppressWarnings("deprecation")
	public static Date getDateYMDHMByStr(String dateStr){
		if(dateStr.contains("T")  && !dateStr.contains("GMT+")) {
			return getDateByStr(dateStr,"yyyy-MM-dd'T'HH:mm");
		}else if(dateStr.contains("GMT+")) {
			//GMT+
			Date date_ = new Date(dateStr);
			String datestr_ = getStrYMDByDate(date_);
			return getDateByStr(datestr_,"yyyy-MM-dd HH:mm");
		}
		return getDateByStr(dateStr,"yyyy-MM-dd HH:mm");
	}
	
	@SuppressWarnings("deprecation")
	public static Date getDateYMDHMSByStr(String dateStr){
		if(dateStr.contains("T")  && !dateStr.contains("GMT+")) {
			return getDateByStr(dateStr,"yyyy-MM-dd'T'HH:mm:ss");
		}else if(dateStr.contains("GMT+")) {
			//GMT+
			Date date_ = new Date(dateStr);
			String datestr_ = getStrYMDByDate(date_);
			return getDateByStr(datestr_,"yyyy-MM-dd HH:mm:ss");
		}
		return getDateByStr(dateStr,"yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * 返回日期的字符串
	 * 
	 * @param date
	 *            Date对象
	 * @param format
	 *            例如:yyyy-MM-dd HH:mm:ss
	 * @return
	 */
	public static String getStrByDate(Date date, String format) {
		DateFormat formatter = getDateFormat(format);
		return formatter.format(date);
	}

	public static String getStrYByDate(Date date) {
		return getStrByDate(date, "yyyy");
	}
	public static String getStrYMByDate(Date date) {
		return getStrByDate(date, "yyyyMM");
	}
	/**
	 * 返回日期的字符串,年-月-日
	 * 
	 * @param date
	 * @return yyyy-MM-dd
	 */
	public static String getStrYMDByDate(Date date) {
		return getStrByDate(date, "yyyy-MM-dd");
	}

	/**
	 * 返回日期的字符串,时:分:秒
	 * 
	 * @param date
	 * @return HH:mm:ss
	 */
	public static String getStrHMSByDate(Date date) {
		return getStrByDate(date, "HH:mm:ss");
	}

	public static String getStrHMByDate(Date date) {
		return getStrByDate(date, "HH:mm");
	}

	/**
	 * 返回日期的字符串,年-月-日 时:分:秒
	 * 
	 * @param date
	 * @return yyyy-MM-dd HH:mm:ss
	 */
	public static String getStrYMDHMSByDate(Date date) {
		return getStrByDate(date, "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * 返回日期的字符串,年月日 时:分
	 * 
	 * @param date
	 * @return yyyy-MM-dd HH:mm
	 */
	public static String getStrYMDHMByDate(Date date) {
		return getStrByDate(date, "yyyy-MM-dd HH:mm");
	}
	public static Date addSecond(Date date, Integer seconds){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.SECOND, seconds);
		return calendar.getTime();
	}
	public static Date addMinute(Date date, Integer minutes){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MINUTE, minutes);
		return calendar.getTime();
	}
	public static Date addHour(Date date, Integer hours){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.HOUR, hours);
		return calendar.getTime();
	}
	/**
	 * 对天数进行加减运算
	 * @param date
	 * @param days
	 * @return
	 */
	public static Date addDay(Date date, Integer days) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DATE, days);
		return calendar.getTime();
	}
	/**
	 * 对月数进行加减运算
	 * @param date
	 * @param months
	 * @return
	 */
	public static Date addMonth(Date date, Integer months) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, months);
		return calendar.getTime();
	}

	/**
	 * 返回中文时间格式
	 * 
	 * @param object
	 *            可以为Date对象或2007-06-12格式的字符串
	 * @return
	 */
	public static String toChinese(Object object) {
		String dateStr = null;
		if (object instanceof Date)
			dateStr = getStrYMDByDate((Date) object);
		else if (object instanceof String)
			dateStr = (String) object;
		else
			return dateStr;
		String[] cnArray = { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
		String year = dateStr.split("-")[0];
		String month = dateStr.split("-")[1];
		String date = dateStr.split("-")[2];
		dateStr = "";
		for (int i = 0; i < year.length(); i++)
			dateStr += cnArray[Integer.valueOf(String.valueOf(year.charAt(i)))];
		dateStr += "年";
		if ("10".equals(month))
			dateStr += "十";
		else {
			int num = Integer.valueOf(String.valueOf(month.charAt(1)));
			if ("0".equals(String.valueOf(month.charAt(0))))
				dateStr += cnArray[num];
			else
				dateStr += "十" + cnArray[num];
		}
		dateStr += "月";
		if ("10".equals(date))
			dateStr += "十";
		else {
			String temp = String.valueOf(date.charAt(0));
			if ("1".equals(temp))
				dateStr += "十";
			else if ("2".equals(temp))
				dateStr += "二十";
			else if ("3".equals(temp))
				dateStr += "三十";
			if (!"0".equals(String.valueOf(date.charAt(1))))
				dateStr += cnArray[Integer.valueOf(String.valueOf(date
						.charAt(1)))];
		}
		dateStr += "日";
		return dateStr;
	}

	public static String toChineseLower(Date date, boolean hasHms) {
		SimpleDateFormat sdf = new java.text.SimpleDateFormat(
				"yyyy-MM-dd HH:mm:ss");
		// System.out.println(sdf.format(date));
		String targetname = sdf.format(date).substring(0, 4) + "年";
		targetname += sdf.format(date).substring(5, 7) + "月";
		targetname += sdf.format(date).substring(8, 10) + "日";
		if (hasHms) {
			targetname += sdf.format(date).substring(11, 13) + "时";
			targetname += sdf.format(date).substring(14, 16) + "分";
			targetname += sdf.format(date).substring(17, 19) + "秒";
		}
		// System.out.println(targetname);
		return targetname;
	}

	/**
	 * 返回星期几
	 * 
	 * @param object
	 *            Date对象或者字符串,yyyy-MM-dd
	 * @return 星期五
	 */
	@SuppressWarnings("deprecation")
	public static String getWeek(Object object) {
		Date date = null;
		if (object instanceof Date)
			date = (Date) object;
		else if (object instanceof String)
			date = getDateByStr((String) object);
		else
			return "";
		String[] cnWeek = { "日", "一", "二", "三", "四", "五", "六" };
		return "星期" + cnWeek[date.getDay()];
	}

	public static Date get00_00_00Date(Date date) {
		return getDateByStr(getStrYMDByDate(date));
	}

	public static Date get23_59_59Date(Date date) {
		return getDateByStr(getStrYMDHMSByDate(date).substring(0, 10)
				+ " 23:59:59");
	}

	public static Date getWeekStartDate_Sunday(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DAY_OF_WEEK, 1);
		return cal.getTime();
	}

	public static Date getWeekStartDate_Monday(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DAY_OF_WEEK, 2);
		return cal.getTime();
	}

	public static Date getWeekEndDate_Sunday(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		if (1 == cal.get(Calendar.DAY_OF_WEEK))
			return date;
		cal.set(Calendar.DAY_OF_WEEK, 1);
		return DateUtil.addDay(cal.getTime(), 7);
	}

	public static Date getWeekEndDate_Saturday(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		if (7 == cal.get(Calendar.DAY_OF_WEEK))
			return date;
		cal.set(Calendar.DAY_OF_WEEK, 7);
		return cal.getTime();
	}

	public static Date getDateByShortStr(String dateStr) {
		try {
			String[] dateStrArray = dateStr.split("-");
			String dateStrYear = "20" + dateStrArray[0];
			String dateStrMonth = dateStrArray[1];
			String dateStrDay = dateStrArray[2];
			if (1 == dateStrMonth.length())
				dateStrMonth = "0" + dateStrMonth;
			if (1 == dateStrDay.length())
				dateStrDay = "0" + dateStrDay;
			return getDateByStr(dateStrYear + "-" + dateStrMonth + "-"
					+ dateStrDay);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	/**
	 * 年份是否相同
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static Boolean isSameYear(Date date1,Date date2){
		Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR);
	}
	/**
	 * 月份是否相同
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static Boolean isSameMonth(Date date1,Date date2){
		Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR) && calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH);
	}
	public static List<String> getDates(String startDate,String endDate){
		List<String> dates = new ArrayList<String>();
		Date start = getDateYMDByStr(startDate);
		Date end = getDateYMDByStr(endDate);
		while(start.getTime() <= end.getTime()) {
			dates.add(getStrYMDByDate(start));
			start = DateUtil.addDay(start, 1);
		}
		return dates;
	}
	/**
	 * 返回SimpleDateFormat
	 * 
	 * @return
	 */
	public static String getSimpleDateFormat() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		return sdf.format(new Date());
	}
	private static final Map<Integer, Character> charMap = new HashMap<Integer, Character>();
    static {  
        charMap.put(1, 'y');  
        charMap.put(2, 'M');  
        charMap.put(3, 'd');  
        charMap.put(4, 'H');  
        charMap.put(5, 'm');  
        charMap.put(6, 's');  
    } 
    /** 
     * 将指定字符串的所有字符替换成指定字符，跳过空白字符 
     * 
     * @param s 被替换字符串 
     * @param c 字符 
     * @return 新字符串 
     */  
    private static String replaceEachChar(String s, Character c) {  
        StringBuilder sb = new StringBuilder("");  
        for (Character c1 : s.toCharArray()) {  
            if (c1 != ' ') {  
                sb.append(String.valueOf(c));  
            }  
        }  
        return sb.toString();  
    } 
    private static final Pattern p = Pattern.compile("^(\\d+)\\D*(\\d*)\\D*(\\d*)\\D*(\\d*)\\D*(\\d*)\\D*(\\d*)");  
    /** 
     * 任意日期字符串转换为Date，不包括无分割的纯数字（13位时间戳除外） ，日期时间为数字，年月日时分秒，但没有毫秒 
     * 
     * @param dateString 日期字符串 
     * @return Date 
     */  
    public static Date stringToDate(String dateString) {  
        dateString = dateString.trim().replaceAll("[a-zA-Z]"," ");  
        if(Pattern.matches("^[-+]?\\d{13}$",dateString)) {//支持13位时间戳  
            return new Date(Long.parseLong(dateString));  
        }  
        Matcher m = p.matcher(dateString);  
        StringBuilder sb = new StringBuilder(dateString);  
        if (m.find(0)) {//从被匹配的字符串中，充index = 0的下表开始查找能够匹配pattern的子字符串。m.matches()的意思是尝试将整个区域与模式匹配，不一样。  
            int count = m.groupCount();  
            for (int i = 1; i <= count; i++) {  
                for (Map.Entry<Integer, Character> entry : charMap.entrySet()) {  
                    if (entry.getKey() == i) {  
                        sb.replace(m.start(i), m.end(i), replaceEachChar(m.group(i), entry.getValue()));  
                    }  
                }  
            }  
        } else {
            return null;  
        }  
        String format = sb.toString();  
        SimpleDateFormat sf = new SimpleDateFormat(format);  
        try {  
            return sf.parse(dateString);  
        } catch (ParseException e) {
            return null;  
        }  
    }
    /**
     * excel日期转java日期
     * @param days
     * @return
     */
    public static Date excelDate2JavaDate(int days) {
		return addDay(new GregorianCalendar(1900,0,-1).getTime(), days);
    }
    public static Date excelDate2JavaDateStr(int days,String format) {
		return addDay(new GregorianCalendar(1900,0,-1).getTime(), days);
    }
    /**
     * 过滤掉非法的日期字符
     * @param datestr
     * @return
     */
    public static String filterIllegalDateStr(final String datestr) {
    	if(StringUtils.isEmpty(datestr)) {
    		return datestr;
    	}
    	if(!isValidDate(datestr)) {
    		return datestr;
    	}
    	try {
    		Date tmpdate = stringToDate(datestr);
    		if(null!=tmpdate) {
    			return datestr;
    		}
    		return getStrYMDHMSByDate(tmpdate);
    	}catch(Exception e) {
    		return datestr;
    	}
    	
    }
    /**
     * 判断字符串是否为日期
     * @param strDate
     * @return
     */
    public static boolean isValidDate(String strDate) {
    	if(StringUtils.isEmpty(strDate)) {
    		return false;
    	}
    	Pattern pattern = Pattern
                .compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$");
        Matcher m = pattern.matcher(strDate);
        if (m.matches()) {
            return true;
        } else {
            return false;
        }
    }
    public static void main(String[] args) {
    	//333%23%
    	//14.7%
//    	Date d = stringToDate("01/1/2019 12:23");
//		System.out.println(getStrYMDHMSByDate(d));
    	
    	Boolean result = isValidDate("2019/1/7");
    	
    	Date ddd = stringToDate("   2019/2/3 16:23  ");
    	System.out.println(ddd);
    	//System.out.println("result:"+result);
	}

}
